package com.jobcn.service;

import com.alibaba.fastjson.JSONObject;
import com.jobcn.config.AbuyunConfig;
import com.jobcn.config.RedisConfig;
import com.jobcn.config.SpiderConfig;
import com.jobcn.dic.SpiderDic;
import com.jobcn.entity.SpiderArea;
import com.jobcn.entity.SpiderSetting;
import com.jobcn.entity.SpiderSort;
import com.jobcn.entity.SpiderTask;
import com.jobcn.repository.spider.*;
import com.jobcn.spider.*;
import com.virjar.dungproxy.webmagic7.DungProxyDownloader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.proxy.Proxy;
import us.codecraft.webmagic.proxy.SimpleProxyProvider;

import java.util.*;

import static com.jobcn.dic.SpiderDic.STATUS_PROCESSING;

/**
 * Created by winson on 17-6-27.
 */
@Service
public class SpiderServiceImpl implements SpiderService {

    final Logger logger = LoggerFactory.getLogger(SpiderServiceImpl.class);
    @Autowired
    private RedisConfig redisConfig;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private SpiderTaskRepository spiderTaskRepository;
    @Autowired
    private SpiderAreaRepository spiderAreaRepository;
    @Autowired
    private SpiderSortRepository spiderSortRepository;
    @Autowired
    private SpiderMerRepository spiderMerRepository;
    @Autowired
    private SpiderInfoRepository spiderInfoRepository;
    @Autowired
    private SpiderSettingRepository spiderSettingRepository;
    @Autowired
    private Pipeline58 pipeline58;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SpiderConfig spiderConfig;
    @Autowired
    private AbuyunConfig abuyunConfig;

    private static Spider58 spider;

    public static Map<String, String> addressCode;
    public static Map<String, Object> sortCode;
    public static Map<String, Integer> checkMap;

    //种子url的拼装
    private static final String seedUrlreg = "http://%s.58.com/%s/";

    @Override
    public Map<String, Object> spider58Stop() {
        Map<String, Object> map = new HashMap<>();
        if (spider != null) {
            spider.stop();
            //增加执行完毕对Task状态的更新
            SpiderTask task = spiderTaskRepository.findOne(spider.getTaskId());
            task.setInfoCount(spiderInfoRepository.countByTaskId(task.getId()));
            task.setMerCount(spiderMerRepository.countByTaskId(task.getId()));
            task.setStatus(SpiderDic.STATUS_EXCEPTION);
            task.setMsg("被拦截,出现验证码");
            task.setUpdateDatetime(new Date());
            spiderTaskRepository.save(task);
            map.put("code", 1);
            map.put("msg", "暂停爬虫");
        } else {
            map.put("code", 0);
            map.put("msg", "没有可以暂停爬虫的");
        }
        return map;
    }

    @Override
    public Map<String, Object> spider58Resume() {
        Map<String, Object> map = new HashMap<>();
        if (spider != null) {
            spider.start();
            SpiderTask task = spiderTaskRepository.findOne(spider.getTaskId());
            task.setStatus(SpiderDic.STATUS_PROCESSING);
            task.setUpdateDatetime(new Date());
            task.setMsg("从暂停中被恢复");
            spiderTaskRepository.save(task);
            map.put("code", 1);
            map.put("msg", "恢复爬虫");
        } else {
            map.put("code", 0);
            map.put("msg", "没有可以恢复的爬虫");
        }
        return map;
    }

    @Override
    public Map<String, Object> spider58Close() {
        Map<String, Object> map = new HashMap<>();
        if (spider != null) {
            spider.close();
            SpiderTask task = spiderTaskRepository.findOne(spider.getTaskId());
            task.setInfoCount(spiderInfoRepository.countByTaskId(task.getId()));
            task.setMerCount(spiderMerRepository.countByTaskId(task.getId()));
            task.setStatus(SpiderDic.STATUS_CLOSE);
            task.setUpdateDatetime(new Date());
            spiderTaskRepository.save(task);
            task.setMsg("终止爬虫");
            map.put("code", 1);
            map.put("msg", "终止爬虫");
        } else {
            map.put("code", 0);
            map.put("msg", "没有可以终止的爬虫");
        }
        return map;
    }

    @Override
    public Map<String, Object> spider58Run(Integer downloadType, SpiderTask task) {
        //先终止已经存在的spider
        if (spider != null)
            spider.close();
        //将所有执行中的任务修改为异常
        List<SpiderTask> spiderTaskList = spiderTaskRepository.findAllByStatusAndTaskType(SpiderDic.STATUS_PROCESSING, SpiderDic.TASK_SPIDER);
        for (SpiderTask spiderTask : spiderTaskList) {
            //统计爬取的数量
            task.setInfoCount(spiderInfoRepository.countByTaskId(task.getId()));
            task.setMerCount(spiderMerRepository.countByTaskId(task.getId()));
            task.setStatus(SpiderDic.STATUS_EXCEPTION);
            task.setMsg("爬虫服务被异常中断");
            spiderTaskRepository.save(task);
        }

        logger.info("开始爬虫");
        long start = System.currentTimeMillis();
        //清除上次的redis缓存
        redisTemplate.delete("set_www.58.com");
        redisTemplate.delete("queue_www.58.com");
        //插入商家服务任务日志
        task.setStartDatetime(new Date());
        task.setStatus(STATUS_PROCESSING);
        task.setUpdateDatetime(new Date());
        task.setMsg("爬虫中");
        task = spiderTaskRepository.save(task);

        //准备地区表,组装地区code和地区的url  如 dg 和3002
        List<SpiderArea> areaCodeList = spiderAreaRepository.findAllByAvailable(true);
        if (addressCode == null)
            addressCode = new HashMap<>();
        if (checkMap == null)
            checkMap = new HashMap<>();
        for (SpiderArea spiderArea : areaCodeList) {
            addressCode.put(spiderArea.getName(), spiderArea.getCode().toString());
        }

        //准备地区和分类配置
        List<SpiderArea> areaList = spiderAreaRepository.findAllByAvailable(true);
        List<SpiderSort> sortList = spiderSortRepository.findAllByAvailable(true);
        List seedUrlList = new ArrayList<>();

        for (SpiderArea spiderArea : areaList) {
            for (SpiderSort spiderSort : sortList) {
                seedUrlList.add(String.format(seedUrlreg, spiderArea.getName(), spiderSort.getName()) + "?renzheng=1");
                checkMap.put(spiderArea.getName() + ".58.com/" + spiderSort.getName(), 0);
            }
        }


        //用于校验分类的map
        for (SpiderSort spiderSort : sortList) {
            if (sortCode == null)
                sortCode = new HashMap<>();
            sortCode.put(spiderSort.getName(), spiderSort.getId());
        }

        //执行商家服务爬虫
        spider = Spider58.create(new Processor58(task.getId(), seedUrlList))
                .addUrl((String[]) seedUrlList.toArray(new String[seedUrlList.size()]))
                .addPipeline(pipeline58)
                .setScheduler(new Scheduler58(redisConfig.getHost()))
                .setTaskId(task.getId())
                .thread(spiderConfig.getThread());

        Downloader downloader = new Downloader();

        //设置下载方式
        switch (downloadType) {
            case 0:
                spider.setDownloader(downloader);
                break;
            case 1:
                downloader.setProxyProvider(SimpleProxyProvider.from(new Proxy(abuyunConfig.getHost(), abuyunConfig.getProt(), abuyunConfig.getUsername(), abuyunConfig.getPassword())));
                spider.setDownloader(downloader);
                break;
            default:
                spider.setDownloader(new DungProxyDownloader());
                break;
        }
        spider.start();
        Map<String, Object> map = new HashMap<>();
        map.put("code", 0);
        map.put("msg", "开启爬虫");
        return map;
    }

    @Override
    public void finishSpider(int taskId) {
        if (!stringRedisTemplate.hasKey("queue_www.58.com")) {
            //爬虫完毕后更新任务状态
            SpiderTask task = spiderTaskRepository.findOne(taskId);
            task.setMerCount(spiderMerRepository.countByTaskId(taskId));
            task.setInfoCount(spiderInfoRepository.countByTaskId(taskId));
            task.setStatus(SpiderDic.STATUS_FINISH);
            task.setUpdateDatetime(new Date());
            task.setEndDatetime(new Date());
            task.setSpiderLog(JSONObject.toJSONString(SpiderServiceImpl.checkMap));
            spiderTaskRepository.save(task);

            //根据设置判断是否需要插入更新任务
            SpiderSetting spiderSetting = spiderSettingRepository.findOne(SpiderDic.SPIDER_SOURCE_58);
            if (spiderSetting.getUpdateStatus()) {
                SpiderTask updateTask = new SpiderTask();
                updateTask.setStatus(SpiderDic.STATUS_WAIT);
                updateTask.setSource(SpiderDic.SPIDER_SOURCE_58);
                updateTask.setMsg("等待执行");
                updateTask.setTriggerType(SpiderDic.TRIGGER_TIMMER);
                updateTask.setUpdateDatetime(new Date());
                updateTask.setTaskType(SpiderDic.TASK_UPDATE);
                spiderTaskRepository.save(updateTask);
            }
        }
    }
}
